package com.onlyMe.world
{
	import com.onlyMe.geom.Coord;
	import com.onlyMe.world.components.ComponentCreator;
	import com.onlyMe.world.objects.IsleObject;
	import com.onlyMe.world.objects.IsleObjectContext;
	import com.onlyMe.world.objects.IsleObjectCreator;
	import com.onlyMe.world.objects.IsleObjectEvent;
	import com.onlyMe.world.path.EightWayPathFinder;
	import com.onlyMe.world.path.PathFinder;
	import com.onlyMe.world.path.TileGridPathMap;
	import com.onlyMe.world.tiling.Tile;
	import com.onlyMe.world.tiling.TileGrid;
	
	import flash.events.EventDispatcher;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.utils.IExternalizable;
	import flash.utils.setTimeout;
	
	// TODO: Generate actual grid
	// TODO: Create IsleObjects and their components
	
	public class Isle extends EventDispatcher implements IsleObjectContext, IExternalizable
	{
		private var _grid:TileGrid;
		
		private var pathfinder:PathFinder;
		private var map:TileGridPathMap;
		
		private var objectCreator:IsleObjectCreator;
		
		public function Isle()
		{
			init();
		}
		
		//-- Utils
		
		private function init():void
		{
			pathfinder = new EightWayPathFinder(true);
			
			objectCreator = new IsleObjectCreator();
			
			_grid = new TileGrid();
			map = new TileGridPathMap(grid);
			
			setTimeout(fillGrid, 1);
		}
		
		private function event(type:String, object:IsleObject=null):void
		{
			dispatchEvent(new IsleEvent(type, object));
		}
		
		private function fillGrid():void
		{
			// TODO
			for (var i:int = 0; i < 75; i++)
				for (var j:int = 0; j < 75; j++)
					_grid.setTileAt(i, j, new Tile('temp!'));
			
			event(IsleEvent.READY);
		}
		
		private function getPath(from:Coord, to:Coord):Array
		{
			var coords:Array = pathfinder.findPath(from, to, map);
			return coords && coords.length > 1 ? coords:null;
		}
		
		public function get grid():TileGrid
		{
			return _grid;
		}
		
		public function getTile(object:IsleObject):Tile
		{
			return grid.getTileAtCoord(object.coord);
		}
		
		//-- IsleObjectContext implementation
		
		public function add(object:IsleObject):void
		{
			getTile(object).addChild(object);
			event(IsleEvent.OBJECT_ADDED, object);
		}
		
		public function remove(object:IsleObject):void
		{
			getTile(object).removeChild(object);
			event(IsleEvent.OBJECT_REMOVED, object);
		}
		
		public function has(object:IsleObject):Boolean
		{
			return getTile(object).hasChild(object);
		}
		
		//-- Serialization
		
		public function readExternal(input:IDataInput):void
		{
			while (input.bytesAvailable)
			{
				var id:int = input.readShort();
				var object:IsleObject = objectCreator.create(id);
				object.readExternal(input);
				object.context = this;
			}
		}
		
		public function writeExternal(output:IDataOutput):void
		{
			for each (var object:IsleObject in grid.findAll())
			{
				output.writeShort(object.id);
				object.writeExternal(output);
			}
		}
	}
}
